﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using DC2010.Objects;
using DC2010.Objects.Base;
using DC2010.Objects.Common;
using DC2010.Objects.Data;
using log4net;
using System.Reflection;

namespace DC2010.Systems
{
    public class GameSystem : BaseSystem
    {
        private static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// Active player party.
        /// </summary>		
        public PartyData Party { get; set; }

        /// <summary>
        /// Layer we are proceeding right now...
        /// </summary>
        public Layer CurrentLayer { get; set; }
        public string ActiveMap { get; set; }

        public string CurrentScreen { get; set; }
        public string CurrentSubScreen { get; set; }

        /// <summary>
        /// For this member Im exploring inventory, etc...
        /// </summary>
        public CreatureData SelectedMember { get; set; }

		#region Flags
        /// <summary>
        /// Duration of how much seconds u see window. Can be increased or decresed as well
        /// </summary>
        public int SeeThruWalls { get; set; }

        /// <summary>
        /// When jumping to the pit ...no damage :)
        /// </summary>
        public int SupressPitDamage { get; set; }

        /// <summary>
        /// Seconds for freeze time.
        /// </summary>
        public int FreezeLifeTimer { get; set; }

        /// <summary>
        /// Light amount. Decreasing with time.
        /// </summary>
        public int Brightness { get; set; }

		#endregion
		
        /// <summary>
        /// Casting bar is displayed for this one....index
        /// </summary>
        public int ActiveCaster { get; set; }

        public ItemData ItemInHand { get; set; }

		// Id of the owner, List<BaseObject> - instantiated objects present in game owned by owner
        protected Dictionary<string, List<BaseObject>> OwnedObjects { get; set; }

		// Wall display
        public string IsAlt { get; set; }


        public override void Init()
        {
            DateTime dtStart = DateTime.Now;
			
            Run();

            log.Info("Core, Game init takes: " + (DateTime.Now - dtStart).TotalSeconds + " seconds");

        }

		#region Ownership (Item do not know who holds it :) U can ask here)
		
        /// <summary>
        /// Adds object to specific owner
        /// </summary>
        /// <param name="ownerId">object id - what object ill be looking for later.</param>
        /// <param name="bo">owner, Creature, Tile, etc...</param>
        public void GiveObject(string ownerId, BaseObject bo)
        {
            //get owner collection
            if (!OwnedObjects.ContainsKey(ownerId))
                OwnedObjects.Add(ownerId, new List<BaseObject>());

            //add object
            OwnedObjects[ownerId].Add(bo);
        }

        /// <summary>
        /// Return owner id which are owned by owner id
        /// </summary>
        /// <param name="objectId">Id of object we are looking for.</param>
        /// <returns>Object owner id if found</returns>		
        public string FindOwner(string objectId)
        {
            foreach (KeyValuePair<string, List<BaseObject>> kvp in OwnedObjects)
            {
                var x = (from i in kvp.Value
                         where i.Id == objectId
                         select i).FirstOrDefault();

                if (x != null)
                    return kvp.Key;
            }

            //not found
            return string.Empty;
        }

        /// <summary>
        /// Return all object which are owned by owner id
        /// </summary>
        /// <param name="ownerId"></param>
        /// <returns></returns>
        public List<BaseObject> GetOwnedObjects(string ownerId)
        {
            if (OwnedObjects.ContainsKey(ownerId))
                return OwnedObjects[ownerId];

            return null;
        }

        /// <summary>
        /// Method will return object im looking for in case this owner has it.
        /// </summary>
        /// <param name="ownerId">Owner id who im checking for the object</param>
        /// <param name="objectId">Object id im looking for.</param>
        /// <returns></returns>
        public BaseObject GetOwnedObject(string ownerId, string objectId)
        {
            List<BaseObject> lst = GetOwnedObjects(ownerId);
            //ok we have all object owned by entity
            //look if our desired id is somewhere there...

            var x = (from i in lst
                     where i.Id == objectId
                     select i).FirstOrDefault();

            return x;
        }
		
		#endregion

		#region Object referencing
        public BaseObject GetReferencedObject(ObjectReference refer)
        {
            switch (refer.ObjectType)
            {
                case BaseObjectType.Creature:
                    {
                        BaseObject boData = Root.I.CreatureSystem.GetData(refer.ReferencedId);
                        if (boData != null) return boData;

                        BaseObject boInfo = Root.I.CreatureSystem.GetInfo(refer.ReferencedId);
                        if (boInfo != null) return boInfo;
						break;
                    }
                case BaseObjectType.Tile:
                    {
                        BaseObject boData = Root.I.TileSystem.GetData(refer.ReferencedId);
                        if (boData != null) return boData;

                        BaseObject boInfo = Root.I.TileSystem.GetInfo(refer.ReferencedId);
                        if (boInfo != null) return boInfo;
                        break;
                    }
                case BaseObjectType.Item:
                    {
                        BaseObject boData = Root.I.ItemSystem.GetData(refer.ReferencedId);
                        if (boData != null) return boData;

                        BaseObject boInfo = Root.I.ItemSystem.GetInfo(refer.ReferencedId);
                        if (boInfo != null) return boInfo;
                        break;
                    }
                case BaseObjectType.Spell:
                    {
                        BaseObject boData = Root.I.SpellSystem.GetData(refer.ReferencedId);
                        if (boData != null) return boData;

                        BaseObject boInfo = Root.I.SpellSystem.GetInfo(refer.ReferencedId);
                        if (boInfo != null) return boInfo;
                        break;
                    }					
            }

            return null;
        }


        public BaseObject GetReferencedObject(List<ObjectReference> refer, BaseObjectType ot, string id)
        {
            var x = (from i in refer
                     where i.ObjectType == ot && i.ReferencedId == id
                     select i).FirstOrDefault();

            if (x!=null)
            {
                return GetReferencedObject(x);
            }

            return null;
        }
		
		#endregion

        public void Run()
        {
            IsAlt = "";
            Root.I.GameSystem.ActiveMap = "FLOOR_EDITOR_TEST";
            FloorInfo fi = Root.I.FloorSystem.GetInfo(Root.I.GameSystem.ActiveMap);

            if (fi == null)
            {
                fi = new FloorInfo();
                fi.Id = "FLOOR_EDITOR_TEST";
                Root.I.FloorSystem.AddInfo(fi);
            }

            FloorData fd = fi.CreateData();

            Root.I.GameSystem.CurrentLayer = fd.TileLayer;

			OwnedObjects = new Dictionary<string, List<BaseObject>>();
            Party = new PartyData();
            Party.Id = "Main_Party";
            Party.Location.X = 10;
            Party.Location.Y = 23;
            Party.Location.FloorId = fd.Id;
            Root.I.PartySystem.AddData(Party);

            ActiveCaster = 1;
            CurrentScreen = "Dungeon";

            // TEST
            CreatureGfx cgfx = new CreatureGfx();
            cgfx.Id = "GFX_PLAGUE";
            cgfx.Face = "Characters/Plague";
            cgfx.Bar = "Interface/Bars/BlueBar";

            CreatureInfo ci = new CreatureInfo();
            ci.GfxId = "GFX_PLAGUE";
            ci.Id = "CHARACTER_PLAGUE";
            ci.ShortName = "TEST";
            ci.Attributes.Health = new CurrentNormal(30, 30);
            ci.Attributes.Mana = new CurrentNormal(30, 30);
            ci.Attributes.Stamina = new CurrentNormal(30, 30);

            ci.Skills[0] = new SKILL();
            ci.Skills[1] = new SKILL();
            ci.Skills[2] = new SKILL();
            ci.Skills[3] = new SKILL();
            ci.Skills[4] = new SKILL();
            ci.Skills[5] = new SKILL();
            ci.Skills[6] = new SKILL();
            ci.Skills[7] = new SKILL();
            ci.Skills[8] = new SKILL();
            ci.Skills[9] = new SKILL();
            ci.Skills[10] = new SKILL();
            ci.Skills[11] = new SKILL();
            ci.Skills[12] = new SKILL();
            ci.Skills[13] = new SKILL();
            ci.Skills[14] = new SKILL();
            ci.Skills[15] = new SKILL();
            ci.Skills[16] = new SKILL();
            ci.Skills[17] = new SKILL();
            ci.Skills[18] = new SKILL();
            ci.Skills[19] = new SKILL();

            Root.I.CreatureSystem.AddGfx(cgfx);
            Root.I.CreatureSystem.AddInfo(ci);

            CreatureData cd = ci.CreateData();
            CreatureData cd1 = ci.CreateData();
            CreatureData cd2 = ci.CreateData();
            CreatureData cd3 = ci.CreateData();

            Party.L.JoinParty(cd);
            Party.L.JoinParty(cd1);
            Party.L.JoinParty(cd2);
            Party.L.JoinParty(cd3);



        }

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="memberId">Member id to switch</param>
        ///// <returns>Which member is selected</returns>
        //public string SelectMember(string memberId)
        //{
        //    SelectedMember = memberId;
        //    return SelectedMember;
        //}

        public delegate void LogDelegate(string p, Color color);
        public event LogDelegate Log_Common;
        public void InGameLog(string p, Color color)
        {
            if (Log_Common != null) Log_Common(p, color);
        }

        public event LogDelegate Log_Debug;
        public void LogDebug(string p)
        {
            if (Log_Debug != null) Log_Debug("DEBUG - " + p, Color.Lime);
        }


		/// <summary>
		/// Possible actions are visible
		/// </summary>
        public void DeactivateAllActions()
        {
            foreach (CreatureData ccc in Root.I.GameSystem.Party.MembersData)
            {
                ccc.ActionOptionsAreDisplayed_Left = false;
                ccc.ActionOptionsAreDisplayed_Right = false;
            }
        }

        public bool IsActionsActivated(CreatureData player, ItemData i)
        {
            foreach (CreatureData c in Root.I.GameSystem.Party.MembersData)
            {
                if (c.ActionOptionsAreDisplayed_Left)
                {
                    player = c;

                    ItemData itmLeft = c.L.Possession(CarryLocations.LeftHand);
                    ItemData itmRight = c.L.Possession(CarryLocations.RightHand);

                    if (itmLeft != null) { i = itmLeft; return true; }
                    if (itmRight != null) { i = itmRight; return true; }
                }

                if (c.ActionOptionsAreDisplayed_Right)
                {
                    player = c;

                    ItemData itmLeft = c.L.Possession(CarryLocations.LeftHand);
                    ItemData itmRight = c.L.Possession(CarryLocations.RightHand);

                    if (itmLeft != null) { i = itmLeft; return true; }
                    if (itmRight != null) { i = itmRight; return true; }
                }

            }

            return false;
        }

        public void AddItem(PartyData pd, ItemData id)
        {
            //find party leader ... party leader is the one who is picking up items...
            CreatureData creatureLeader = pd.L.GetLeader();

            //pickup item
            creatureLeader.L.PickupItem(id);
        }

        /// <summary>
        /// Add message to Main window
        /// </summary>
        /// <param name="color"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public bool QuePrintLines(int color, string message)
        {
            // Add message to Main window
            return true;
        }

        public void DisableCharacterAction(CreatureData pChar, int p)
        {
            //throw new NotImplementedException();
        }
		
		public void TenSecondsUpdate()
		{
			
		}

        public void InvertAlt()
        {
            switch(IsAlt)
            {
                case "": IsAlt="Alt";break;
                case "Alt": IsAlt="";break;
            }
        }
    }
}
